#include "gpssimcommunication.h"
#include <assert.h>
#include <QString>
#include <QTcpSocket>
#include <QHostAddress>
#include "CNetworkFactory.h"
#include "inetworking.h"

extern GPSSimCommunication socketCom;

GPSSimCommunication * GPSSimCommunication::m_spSocketCommunication = NULL;
QString GPSSimCommunication::m_IP = "";
int GPSSimCommunication::m_port = 0;

void GPSSimCommunication::InitInstance()
{
    // if we have initialize an instance, then send out an error
    assert(m_spSocketCommunication == NULL);

    m_spSocketCommunication = new GPSSimCommunication();
}

GPSSimCommunication* GPSSimCommunication::GetInstance()
{
    assert(m_spSocketCommunication != NULL);

    return m_spSocketCommunication;
}

void GPSSimCommunication::Destroy()
{
    assert(m_spSocketCommunication != NULL);

    delete m_spSocketCommunication;
}

GPSSimCommunication::GPSSimCommunication()
{
    pNetWorking = NULL;
    param = NULL;
    nextBlockSize = 0;

    connect(&tcpSocket, SIGNAL(connected() ), this, SLOT(hasConnected()) );
    connect(&tcpSocket, SIGNAL(disconnected() ), this, SLOT(connectionClosedByServer()) );
    connect(&tcpSocket, SIGNAL(readyRead() ), this, SLOT(readyRead()) );
    connect(&tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)) , this, SLOT(error()) );
}

GPSSimCommunication::~GPSSimCommunication()
{
    if (param != NULL)
    {
        delete [] param;
    }
}

void GPSSimCommunication::connectToServer(QString serverIP, unsigned short port)
{
    assert(serverIP.isEmpty() != true && port != 0);

    QHostAddress address(serverIP);

    tcpSocket.connectToHost(address, port);
}

void GPSSimCommunication::connectToServer()
{
    connectToServer(m_IP, m_port);
}

//void GPSSimCommunication::setupNetworkingClass(INetWorking* networkingclass)
//{
//    pNetWorking = networkingclass;
//}

void GPSSimCommunication::sendRequest(int command, void *para, int size)
{
    // parameter can be null
    if ( (para == NULL && size != 0) || (param != NULL && size == 0) )
    {
        qDebug() << "parameter and size error\n";
        assert(0);
    }

    this->command = command;

    if (this->param != NULL)
    {
        delete [] this->param;
        this->param = NULL;
    }

    if (para != NULL && size != 0)
    {
        this->param = new char [size];
        memcpy(param , para, size);
    }

    // use the command only to get the working class
    pNetWorking = CNetworkFactory::getNetworkClass(this->command);

    connect(pNetWorking, SIGNAL(SendAndRecieveDifferentError()) , this, SLOT(SendAndRevieveDifferentError()) );

    // send the infomation
    QByteArray block;

    pNetWorking->setData(this->param, &block);

    tcpSocket.write(block);

    tcpSocket.flush();
}

void GPSSimCommunication::stopRequest()
{
    this->closeConnection();
}

void GPSSimCommunication::closeConnection()
{
    tcpSocket.close();
}

void GPSSimCommunication::readyRead()
{
    pNetWorking->recieveData(tcpSocket.bytesAvailable(), &tcpSocket);

    //this->closeConnection();

    emit canReadGPS();
}

void GPSSimCommunication::connectionClosedByServer()
{
    // emit the closeByServer signal, indicating that the communication was closed by server
    emit closeByServerGPS();

    this->closeConnection();
}

void GPSSimCommunication::error()
{
    socketErrors = tcpSocket.errorString();

    qDebug() << "error has been met" << socketErrors << "\n";

    emit socketErrorGPS();

    this->closeConnection();
}

void GPSSimCommunication::SendAndRevieveDifferentError()
{
    qDebug() << "Send And Revieve Different Error\n";

    this->closeConnection();
}

QMap<QString, QString>* GPSSimCommunication::getResult()
{
    return pNetWorking->getResult();
}

QString GPSSimCommunication::getResult(QString name)
{
    return pNetWorking->getResult(name);
}

void GPSSimCommunication::hasConnected()
{
    qDebug() << "connect has been established, is sending request\n";

    emit GPSConnected();
}

bool GPSSimCommunication::isFatalError()
{
    int errorCode = tcpSocket.error();
    if (   errorCode == QAbstractSocket::SocketTimeoutError
        || errorCode == QAbstractSocket::NetworkError
        || errorCode == QAbstractSocket::SslHandshakeFailedError
        || errorCode == QAbstractSocket::ProxyConnectionClosedError
        || errorCode == QAbstractSocket::ProxyConnectionTimeoutError)
    {
        return false;
    }

    return true;
}
